home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 21 / Cream of the Crop 21 (Terry Blount) (October 1996).iso / os2 / e33el2.zip / emacs / 19.33 / lisp / ediff-ptch.el < prev    next >
Lisp/Scheme  |  1996-07-02  |  21KB  |  563 lines

  1. ;;; ediff-ptch.el --- Ediff's  patch support
  2.  
  3. ;; Copyright (C) 1996 Free Software Foundation, Inc.
  4.  
  5. ;; Author: Michael Kifer <kifer@cs.sunysb.edu>
  6.  
  7. ;; This file is part of GNU Emacs.
  8.  
  9. ;; GNU Emacs is free software; you can redistribute it and/or modify
  10. ;; it under the terms of the GNU General Public License as published by
  11. ;; the Free Software Foundation; either version 2, or (at your option)
  12. ;; any later version.
  13.  
  14. ;; GNU Emacs is distributed in the hope that it will be useful,
  15. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17. ;; GNU General Public License for more details.
  18.  
  19. ;; You should have received a copy of the GNU General Public License
  20. ;; along with GNU Emacs; see the file COPYING.  If not, write to the
  21. ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  22. ;; Boston, MA 02111-1307, USA.
  23.  
  24.  
  25. ;;; Code:
  26.  
  27. (defvar ediff-last-dir-patch nil
  28.   "Last directory used by an Ediff command for file to patch.")
  29.  
  30. (defvar ediff-backup-extension 
  31.   (if (memq system-type '(vax-vms axp-vms emx ms-dos windows-nt windows-95))
  32.       "_orig" ".orig")
  33.   "Default backup extension for the patch program.")
  34.  
  35. (defvar ediff-patch-default-directory nil
  36.   "*Default directory to look for patches.")
  37.  
  38. (defvar ediff-context-diff-label-regexp
  39.   (concat "\\("     ; context diff 2-liner
  40.       "^\\*\\*\\* \\([^ \t]+\\)[^*]+[\t ]*\n--- \\([^ \t]+\\)"
  41.       "\\|"     ; GNU unified format diff 2-liner
  42.       "^--- \\([^ \t]+\\)[^-]+[\t ]*\n\\+\\+\\+ \\([^ \t]+\\)"
  43.       "\\)")
  44.   "*Regexp matching filename 2-liners at the start of each context diff.")
  45.  
  46. (defvar ediff-patch-program "patch"
  47.   "*Name of the program that applies patches.")
  48. (defvar ediff-patch-options ""
  49.   "*Options to pass to ediff-patch-program.")
  50.  
  51. ;; The buffer of the patch file. Local to control buffer.
  52. (ediff-defvar-local ediff-patchbufer nil "")
  53.  
  54. ;; The buffer where patch displays its diagnostics.
  55. (ediff-defvar-local ediff-patch-diagnostics nil "")
  56.  
  57. ;; Map of patch buffer. Has the form:
  58. ;;    ((filename1 marker1 marker2) (filename2 marker1 marker2) ...)
  59. ;; where filenames are files to which patch would have applied the patch;
  60. ;; marker1 delimits the beginning of the corresponding patch and marker2 does
  61. ;; it for the end.
  62. (ediff-defvar-local ediff-patch-map nil "")
  63.  
  64. ;; strip prefix from filename
  65. ;; returns /dev/null, if can't strip prefix
  66. (defsubst ediff-file-name-sans-prefix (filename prefix)
  67.   (save-match-data
  68.     (if (string-match (concat "^" prefix) filename)
  69.     (substring filename (match-end 0))
  70.       (concat "/null/" filename))))
  71.  
  72.  
  73.  
  74. ;; no longer used
  75. ;; return the number of matches of regexp in buf starting from the beginning
  76. (defun ediff-count-matches (regexp buf)
  77.   (ediff-eval-in-buffer buf
  78.     (let ((count 0) opoint)
  79.       (save-excursion
  80.     (goto-char (point-min))
  81.     (while (and (not (eobp))
  82.             (progn (setq opoint (point))
  83.                (re-search-forward regexp nil t)))
  84.       (if (= opoint (point))
  85.           (forward-char 1)
  86.         (setq count (1+ count)))))
  87.       count)))
  88.  
  89. ;; Scan BUF (which is supposed to contain a patch) and make a list of the form 
  90. ;;    ((filename1 marker1 marker2) (filename2 marker1 marker2) ...)
  91. ;; where filenames are files to which patch would have applied the patch;
  92. ;; marker1 delimits the beginning of the corresponding patch and marker2 does
  93. ;; it for the end. This list is then assigned to ediff-patch-map.
  94. ;; Returns the number of elements in the list ediff-patch-map
  95. (defun ediff-map-patch-buffer (buf)
  96.   (ediff-eval-in-buffer buf
  97.     (let ((count 0)
  98.       (mark1 (move-marker (make-marker) (point-min)))
  99.       (mark1-end (point-min))
  100.       (possible-file-names '("/dev/null" . "/dev/null"))
  101.       mark2-end mark2 filenames
  102.       beg1 beg2 end1 end2
  103.       patch-map opoint)
  104.       (save-excursion
  105.     (goto-char (point-min))
  106.     (setq opoint (point))
  107.     (while (and (not (eobp))
  108.             (re-search-forward ediff-context-diff-label-regexp nil t))
  109.       (if (= opoint (point))
  110.           (forward-char 1) ; ensure progress towards the end
  111.         (setq mark2 (move-marker (make-marker) (match-beginning 0))
  112.           mark2-end (match-end 0)
  113.           beg1 (match-beginning 2)
  114.           end1 (match-end 2)
  115.           beg2 (match-beginning 3)
  116.           end2 (match-end 3))
  117.         ;; possible-file-names is holding the new file names until we
  118.         ;; insert the old file name in the patch map
  119.         ;; It is a pair (filename from 1st header line . fn from 2nd line)
  120.         (setq possible-file-names
  121.           (cons (if (and beg1 end1)
  122.                 (buffer-substring beg1 end1)
  123.               "/dev/null")
  124.             (if (and beg2 end2)
  125.                 (buffer-substring beg2 end2)
  126.               "/dev/null")))
  127.         ;; check for any `Index:' or `Prereq:' lines, but don't use them
  128.         (if (re-search-backward "^Index:" mark1-end 'noerror)
  129.         (move-marker mark2 (match-beginning 0)))
  130.         (if (re-search-backward "^Prereq:" mark1-end 'noerror)
  131.         (move-marker mark2 (match-beginning 0)))
  132.  
  133.         (goto-char mark2-end)
  134.         
  135.         (if filenames
  136.         (setq patch-map (cons (list filenames mark1 mark2) patch-map)))
  137.         (setq mark1 mark2
  138.           mark1-end mark2-end
  139.           filenames possible-file-names))
  140.       (setq opoint (point)
  141.         count (1+ count))))
  142.       (setq mark2 (point-max-marker)
  143.         patch-map (cons (list possible-file-names mark1 mark2) patch-map))
  144.       (setq ediff-patch-map (nreverse patch-map))
  145.       count)))
  146.  
  147. ;; Fix up the file names in the list using the argument FILENAME
  148. ;; Algorithm: find the first file's directory and cut it out from each file
  149. ;; name in the patch. Prepend the directory of FILENAME to each file in the
  150. ;; patch. In addition, the first file in the patch is replaced by FILENAME.
  151. ;; Each file is actually a file-pair of files found in the context diff header
  152. ;; In the end, for each pair, we select the shortest existing file.
  153. ;; Note: Ediff doesn't recognize multi-file patches that are separated
  154. ;; with the `Index:' line. It treats them as a single-file patch.
  155. ;;
  156. ;; Executes inside the patch buffer
  157. (defun ediff-fixup-patch-map (filename)
  158.   (setq filename (expand-file-name filename))
  159.   (let ((actual-dir (if (file-directory-p filename)
  160.             ;; directory part of filename
  161.             (file-name-as-directory filename)
  162.               (file-name-directory filename)))
  163.     ;; directory part of the first file in the patch
  164.     (base-dir1 (file-name-directory (car (car (car ediff-patch-map)))))
  165.     (base-dir2 (file-name-directory (cdr (car (car ediff-patch-map)))))
  166.     )
  167.  
  168.     ;; chop off base-dirs
  169.     (mapcar (function (lambda (triple)
  170.             (or (string= (car (car triple)) "/dev/null")
  171.                 (setcar (car triple)
  172.                     (ediff-file-name-sans-prefix
  173.                      (car (car triple)) base-dir1)))
  174.             (or (string= (cdr (car triple)) "/dev/null")
  175.                 (setcdr (car triple)
  176.                     (ediff-file-name-sans-prefix
  177.                      (cdr (car triple)) base-dir2)))
  178.             ))
  179.         ediff-patch-map)
  180.  
  181.     ;; take the given file name into account
  182.     (or (file-directory-p filename)
  183.     (string= "/dev/null" filename)
  184.     (progn
  185.       (setcar (car ediff-patch-map)
  186.           (cons (file-name-nondirectory filename)
  187.             (file-name-nondirectory filename)))))
  188.  
  189.     ;; prepend actual-dir
  190.     (mapcar (function (lambda (triple)
  191.              (if (and (string-match "^/null/" (car (car triple)))
  192.                   (string-match "^/null/" (cdr (car triple))))
  193.                  ;; couldn't strip base-dir1 and base-dir2
  194.                  ;; hence, something wrong
  195.                  (progn
  196.                    (with-output-to-temp-buffer ediff-msg-buffer
  197.                  (princ
  198.                   (format "
  199. The patch file contains a context diff for
  200.     %s
  201.     %s
  202.  
  203. However, Ediff cannot infer the name of the actual file
  204. to be patched on your system. If you know the correct file name,
  205. please enter it now.
  206.  
  207. If you don't know and still would like to apply patches to
  208. other files, enter /dev/null
  209. "
  210.                       (substring (car (car triple)) 6)
  211.                       (substring (cdr (car triple)) 6))))
  212.                    (let ((directory t)
  213.                      user-file)
  214.                  (while directory
  215.                    (setq user-file
  216.                      (read-file-name
  217.                       "Please enter file name: "
  218.                       actual-dir actual-dir t))
  219.                    (if (not (file-directory-p user-file))
  220.                        (setq directory nil)
  221.                      (setq directory t)
  222.